package net.homeip.jcperera.nu.core.boot;

import java.io.Serializable;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import net.homeip.jcperera.nu.core.CoreBase;
import net.homeip.jcperera.nu.core.config.Configuration;
import net.homeip.jcperera.nu.core.msg.Logger;
import net.homeip.jcperera.nu.core.msg.Logging;
import net.homeip.jcperera.nu.core.persistence.Persistence;
import net.homeip.jcperera.nu.model.entity.TypeManager;
import net.homeip.jcperera.nu.security.user.User;

/**
 * Session Bean implementation class SystemBean<br/>
 * Holds System Wide Entities
 * 
 * @name SystemBean class
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0
 */

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
@ApplicationScoped
@LocalBean
@Named(System.componentName)
public class System extends CoreBase implements Serializable
{
    // Required to implement Serializable interface
    private static final long   serialVersionUID = 1949472993958888985L;

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int     runtimeLevel     = 0;
    public static final String  moduleName       = "core";
    public static final String  componentName    = "nu_core_system_bean";

    // Get the log
    private final static Logger log              = Logger.getLogger();

    @EJB
    private Configuration       configuration;

    @EJB
    private Persistence         persistence;

    @EJB
    private Logging             logging;

    @EJB
    private TypeManager         typeManager;

    @Inject
    private User                systemUser;

    /**
     * <p>
     * Starts the {@linkplain System} (framework) by initializing all the corresponding system-level entities and
     * services.
     * </p>
     * <p>
     * The parameters for connection are default values, their values will be usually overwritten by a properties file
     * with the correct configuration.
     * </p>
     * 
     * @param nudbclass
     *            The class for the default JDBC driver to connect to the the default database
     * @param nudburl
     *            The JDBC URL to connect to the the default database using the default JDBC connection
     * @param nudbuser
     *            The database user to connect to the the default database using the default JDBC connection
     * @param nudbpass
     *            The password for the user to connect to the the default database using the default JDBC connection
     * @throws Exception
     *             in case something goes wrong with the initialization, the framework stops and the exception specifies
     *             the error and the cause
     */
    public void start(String nudbclass, String nudburl, String nudbuser, String nudbpass) throws Exception
    {
        configuration.initialize(nudbclass, nudburl, nudbuser, nudbpass);
        logging.start();
        persistence.start();
        configuration.start();
        initializeSystemUser();
        typeManager.start();
    }

    /**
     * Stops the {@linkplain System} (framework) by releasing all resources taken during initialization
     */
    public void stop()
    {
        typeManager.stop();
        configuration.stop();
        persistence.stop();
        logging.stop();
    }

    public Configuration getConfiguration()
    {
        return configuration;
    }

    public Persistence getPersistence()
    {
        return persistence;
    }

    public TypeManager getTypeManager()
    {
        return typeManager;
    }

    private void initializeSystemUser()
    {
        log.info("Initializing System User...");
        if (systemUser == null) systemUser = new User();
        systemUser.getIdTag().setValue("system");
    }

    /**
     * <p>
     * The System User is a kind of "distinguished user" who is responsible for most (if not all) the operations that
     * take place outside the context of a logged-in user, meaning things like "cron" (periodic execution tasks),
     * initializations and other background jobs that are unrelated to a user Session.
     * </p>
     * <p>
     * The System User is unique for an entire application and it does not need to be persisted as it always exists
     * inside the running server (it's launched at bootstrap), you should also take into account that the System User
     * should have all privileges inside the running system, so there is not a good practice to conduct privilege checks
     * on it, as all privileges should return positive if related to the System User.
     * </p>
     * <p>
     * Functionality that need the System User for some need, can access it from here.
     * </p>
     * <p>
     * <b>Note:</b> The login associated to the System User is <code>system</code>, so you are not allowed to create a
     * user account using this "distinguished" login
     * </p>
     * 
     * @return the systemUser
     */
    public User getSystemUser()
    {
        if (systemUser == null)
        {
            systemUser = new User();
            systemUser.getIdTag().setValue("system");
        }
        return systemUser;
    }

    /**
     * Returns a reference to the {@link Logging} EJB
     * 
     * @return the system-wide level instance of the {@link Logging} EJB
     */
    public Logging getLogging()
    {
        return logging;
    }
}
